home *** CD-ROM | disk | FTP | other *** search
/ SGI Freeware 1998 June / SGI Freeware 1998 June.iso / dist / fw_ATxgopher.idb / usr / freeware / src / xgopher.1.3 / gui.c.z / gui.c
C/C++ Source or Header  |  1998-01-21  |  31KB  |  1,332 lines

  1. /* gui.c
  2.    Implement functions of the GUI (Graphical User Interface).  
  3.    The GUI is the X window system.  This file is the interface
  4.    to all other X-related functions in panel.c, error.c, save.c,
  5.    text.c, etc. */
  6.  
  7.      /*---------------------------------------------------------------*/
  8.      /* Xgopher        version 1.3     08 April 1993                  */
  9.      /*                version 1.2     20 November 1992               */
  10.      /*                version 1.1     20 April 1992                  */
  11.      /*                version 1.0     04 March 1992                  */
  12.      /* X window system client for the University of Minnesota        */
  13.      /*                                Internet Gopher System.        */
  14.      /* Allan Tuchman, University of Illinois at Urbana-Champaign     */
  15.      /*                Computing and Communications Services Office   */
  16.      /* Copyright 1992, 1993 by                                       */
  17.      /*           the Board of Trustees of the University of Illinois */
  18.      /* Permission is granted to freely copy and redistribute this    */
  19.      /* software with the copyright notice intact.                    */
  20.      /*---------------------------------------------------------------*/
  21.  
  22.  
  23. #include <stdio.h>
  24. #include <X11/Intrinsic.h>
  25. #include <X11/StringDefs.h>
  26. #include <X11/Shell.h>
  27. #include <X11/Xaw/Simple.h>    /* where XtNcursor is */
  28. #include <X11/Xmu/Converters.h>
  29. #include <X11/cursorfont.h>
  30. #include <X11/Xaw/Text.h>
  31.  
  32.  
  33. #include "conf.h"
  34. #include "gui.h"
  35. #include "panel.h"
  36. #include "error.h"
  37. #include "globals.h"
  38. #include "xglobals.h"
  39. #include "appres.h"
  40. #include "popres.h"
  41. #include "typeres.h"
  42. #include "util.h"
  43. #include "status.h"
  44. #include "compatR4.h"
  45. #include "itemList.h"
  46. #include "dirList.h"
  47. #include "markList.h"
  48. #include "itemInfo.h"
  49. #include "help.h"
  50. #include "cso.h"
  51. #include "index.h"
  52. #include "text.h"
  53. #include "options.h"
  54. #include "single.h"
  55. #include "gopher.h"
  56.  
  57. #include "osdep.h"
  58.  
  59.  
  60. gopherAppResources * getApplicationResources(
  61. );
  62.  
  63.  
  64. static    Widget    topLevel;
  65. static    Boolean    windowStarted = False;
  66.  
  67. static    Boolean errorDialogExists = FALSE;
  68. static    Boolean infoDialogExists = FALSE;
  69. static    Boolean saveDialogExists = FALSE;
  70. static    Boolean csoPanelExists = FALSE;
  71. static    Boolean indexPanelExists = FALSE;
  72. static    Boolean optionsPanelExists = FALSE;
  73. static    Boolean singlePanelExists = FALSE;
  74.  
  75. static  XtWorkProcId nullWPID    = (XtWorkProcId) 0;
  76. static  XtWorkProcId saveWPID    = (XtWorkProcId) 0,
  77.              indexWPID   = (XtWorkProcId) 0,
  78.              csoWPID     = (XtWorkProcId) 0,
  79.              errWPID     = (XtWorkProcId) 0,
  80.              infoWPID    = (XtWorkProcId) 0,
  81.              optionsWPID = (XtWorkProcId) 0,
  82.              singleWPID  = (XtWorkProcId) 0;
  83.  
  84. static char    *emptyList[] = {"<none>", NULL};
  85.  
  86.  
  87. static     String    fallbackResources[] = {
  88.             "",
  89.             (char *) NULL
  90.             };
  91.  
  92.  
  93. /* initGUI
  94.    Initialize the X window system */
  95.  
  96. BOOLEAN
  97. initGUI(argc, argv)
  98. int    *argc;
  99. char    **argv;
  100. {
  101.     static XtPointer    scr;
  102.     static XtConvertArgRec screenConvertArg[] = {
  103.         {XtAddress, (XtPointer)&scr, sizeof(Screen *)}
  104.         };
  105.     Arg            args[5];
  106.     XrmOptionDescRec    opts[2];
  107.     Cardinal        narg = (Cardinal) 0,
  108.                 nopt = (Cardinal) 0;
  109. #ifndef XGOPHER_X11R4
  110.     int            *cArgc = argc;
  111. #else
  112.     Cardinal        *cArgc = (Cardinal *) argc;
  113. #endif
  114.  
  115.         /* initialize X window system */
  116.  
  117.         topLevel   = XtAppInitialize (&appcon, GOPHER_CLASS,
  118.                         opts, nopt, cArgc, argv,
  119.             fallbackResources, args, narg);
  120.  
  121.     scr = (XtPointer) XtScreen(topLevel);
  122.     XtAppAddConverter(appcon, XtRString, XtRPixmap, XmuCvtStringToBitmap,
  123.             screenConvertArg, XtNumber(screenConvertArg));
  124.  
  125.     XtAppSetTypeConverter(appcon, XtRString, XgRShowLevel,
  126.             (XtTypeConverter) cvtStringToShowLevel,
  127.             NULL, (Cardinal) 0,
  128.             XtCacheNone, NULL); 
  129.  
  130.     XtAppSetTypeConverter(appcon, XtRString, XgRPositionFrom,
  131.             (XtTypeConverter) cvtStringToPositionFrom,
  132.             NULL, (Cardinal) 0,
  133.             XtCacheNone, NULL); 
  134.  
  135.     XtAppSetTypeConverter(appcon, XtRString, XgRJustification,
  136.             (XtTypeConverter) cvtStringToJustification,
  137.             NULL, (Cardinal) 0,
  138.             XtCacheNone, NULL); 
  139.  
  140.     XtAppSetTypeConverter(appcon, XtRString, XgRCopyType,
  141.             (XtTypeConverter) cvtStringToCopyType,
  142.             NULL, (Cardinal) 0,
  143.             XtCacheNone, NULL); 
  144.         
  145.     if (! getOptions(*argc, argv)) return FALSE;
  146.  
  147.     windowStarted = True;
  148.  
  149.     return TRUE;
  150. }
  151.  
  152.  
  153. /* "done" macro from the Xmu library - used by those type converters */
  154.  
  155. #define    done(type, value) \
  156.     {                            \
  157.         if (toVal->addr != NULL) {                \
  158.         if (toVal->size < sizeof(type)) {        \
  159.             toVal->size = sizeof(type);            \
  160.             return False;                \
  161.         }                        \
  162.         *(type*)(toVal->addr) = (value);        \
  163.         }                            \
  164.         else {                        \
  165.         static type static_val;                \
  166.         static_val = (value);                \
  167.         toVal->addr = (XtPointer)&static_val;        \
  168.         }                            \
  169.         toVal->size = sizeof(type);                \
  170.         return True;                    \
  171.     }
  172.  
  173.  
  174. /* cvtStringToShow
  175.    type converter for show resource keywords to enumerated type values */
  176.  
  177. Boolean
  178. cvtStringToShowLevel(dpy, args, numArgs, fromVal, toVal, closureRet)
  179. Display        *dpy;
  180. XrmValuePtr    args;
  181. Cardinal    *numArgs;
  182. XrmValuePtr    fromVal, toVal;
  183. XtPointer    *closureRet;
  184. {
  185.     char    *s = (char *) fromVal->addr;
  186.  
  187.     if (s == NULL) return;
  188.  
  189.     if (strcasecmp(showEAll, s) == 0)
  190.                     done( int, (int) showAll );
  191.     if (strcasecmp(showEKnown, s) == 0)
  192.                     done( int, (int) showKnown );
  193.     if (strcasecmp(showEAccessible, s) == 0)
  194.                     done( int, (int) showAccessible );
  195.     if (strcasecmp(showEAvailable, s) == 0)
  196.                     done( int, (int) showAvailable );
  197.  
  198.     XtDisplayStringConversionWarning(dpy, s, XgRShowLevel);
  199.     return False;
  200. }
  201.  
  202.  
  203. /* cvtStringToPositionFrom
  204.    type converter for positionFrom resource to enumerated type values */
  205.  
  206. Boolean
  207. cvtStringToPositionFrom(dpy, args, numArgs, fromVal, toVal, closureRet)
  208. Display        *dpy;
  209. XrmValuePtr    args;
  210. Cardinal    *numArgs;
  211. XrmValuePtr    fromVal, toVal;
  212. XtPointer    *closureRet;
  213. {
  214.     char    *s = (char *) fromVal->addr;
  215.  
  216.     if (s == NULL) return;
  217.  
  218.     if (strcasecmp(fromENone, s) == 0)
  219.                     done( int, (int) from_none );
  220.     if (strcasecmp(fromEPointer, s) == 0)
  221.                     done( int, (int) from_pointer );
  222.     if (strcasecmp(fromEMain, s) == 0)
  223.                     done( int, (int) from_main );
  224.     if (strcasecmp(fromEScreen, s) == 0)
  225.                     done( int, (int) from_screen );
  226.     if (strcasecmp(fromEWidget, s) == 0)
  227.                     done( int, (int) from_widget );
  228.  
  229.     XtDisplayStringConversionWarning(dpy, s, XgRPositionFrom);
  230.     return False;
  231. }
  232.  
  233.  
  234. /* cvtStringToJustification
  235.    type converter for Justification resource to enumerated type values */
  236.  
  237. Boolean
  238. cvtStringToJustification(dpy, args, numArgs, fromVal, toVal, closureRet)
  239. Display        *dpy;
  240. XrmValuePtr    args;
  241. Cardinal    *numArgs;
  242. XrmValuePtr    fromVal, toVal;
  243. XtPointer    *closureRet;
  244. {
  245.     char    *s = (char *) fromVal->addr;
  246.  
  247.     if (s == NULL) return;
  248.  
  249.     if (strcasecmp(justETop, s) == 0  || strcasecmp(justELeft, s) == 0 )
  250.                     done( int, (int) justify_top_left );
  251.     if (strcasecmp(justECenter, s) == 0)
  252.                     done( int, (int) justify_center );
  253.     if (strcasecmp(justEBottom, s) == 0 || strcasecmp(justERight, s) == 0)
  254.                     done( int, (int) justify_bottom_right );
  255.  
  256.     XtDisplayStringConversionWarning(dpy, s, XgRJustification);
  257.     return False;
  258. }
  259.  
  260.  
  261. /* cvtStringToCopyType
  262.    type converter for datatype resource keywords to enumerated type values */
  263.  
  264. Boolean
  265. cvtStringToCopyType(dpy, args, numArgs, fromVal, toVal, closureRet)
  266. Display        *dpy;
  267. XrmValuePtr    args;
  268. Cardinal    *numArgs;
  269. XrmValuePtr    fromVal, toVal;
  270. XtPointer    *closureRet;
  271. {
  272.     char    *s = (char *) fromVal->addr;
  273.  
  274.     if (s == NULL) return;
  275.  
  276.     if (strcasecmp(copyTypeENone, s) == 0)
  277.                     done( int, (int) copyTypeNone );
  278.     if (strcasecmp(copyTypeEAscii, s) == 0)
  279.                     done( int, (int) copyTypeAscii );
  280.     if (strcasecmp(copyTypeEBinary, s) == 0  ||
  281.         strcasecmp(copyTypeEBinaryEOF, s) == 0)
  282.                     done( int, (int) copyTypeBinaryEOF );
  283.     if (strcasecmp(copyTypeEUnspec, s) == 0)
  284.                     done( int, (int) copyTypeUnspec );
  285.  
  286.     XtDisplayStringConversionWarning(dpy, s, XgRCopyType);
  287.     return False;
  288. }
  289.  
  290.  
  291. /* initMainPanel
  292.    creates the main Xgopher panel */
  293.  
  294. BOOLEAN
  295. initMainPanel()
  296. {
  297.  
  298.     makeGopherPanel(topLevel);
  299.  
  300.     XtRealizeWidget(topLevel);
  301.  
  302.     makeStatusPanel(topLevel);
  303. }
  304.  
  305.  
  306. /* getOptions
  307.    Use the GUI (X window system) to access application options */
  308.  
  309. static BOOLEAN
  310. getOptions(argc, argv)
  311. int    argc;
  312. char    **argv;
  313. {
  314.     if ((appResources = getApplicationResources(topLevel, argc, argv)) ==
  315.                                     NULL) 
  316.         return False;
  317.     else
  318.         return True;
  319. }
  320.  
  321.  
  322. /* closeGUIandQuit
  323.    terminate the GUI (X window system) cleanly, then exit the application */
  324.  
  325. void
  326. closeGUIandQuit(rc)
  327. int    rc;
  328. {
  329.     XtDestroyApplicationContext(appcon);
  330.     exit(rc);
  331. }
  332.  
  333.  
  334. /* loadMarks
  335.    load bookmarks from the bookmark file */
  336.  
  337. void
  338. loadMarks()
  339. {
  340.     markLoadProc(NULL, NULL, NULL);
  341. }
  342.  
  343.  
  344. /* makeSaveDialogWorkProc
  345.    X work proc to create the Save Dialog during spare cycles. */
  346.  
  347. static Boolean
  348. makeSaveDialogWorkProc(clientData)
  349. XtPointer    clientData;
  350. {
  351.     Widget        topLevel = (Widget) clientData;
  352.     makeSaveDialog(topLevel);
  353.     saveDialogExists = TRUE;
  354.     return TRUE;
  355. }
  356.  
  357.  
  358. /* makeInfoDialogWorkProc
  359.    X work proc to create the Info Dialog during spare cycles. */
  360.  
  361. static Boolean
  362. makeInfoDialogWorkProc(clientData)
  363. XtPointer    clientData;
  364. {
  365.     Widget        topLevel = (Widget) clientData;
  366.     makeInfoDialog(topLevel);
  367.     infoDialogExists = TRUE;
  368.     return TRUE;
  369. }
  370.  
  371.  
  372. /* makeErrorDialogWorkProc
  373.    X work proc to create the Error Dialog during spare cycles. */
  374.  
  375. static Boolean
  376. makeErrorDialogWorkProc(clientData)
  377. XtPointer    clientData;
  378. {
  379.     Widget        topLevel = (Widget) clientData;
  380.     makeErrorDialog(topLevel);
  381.     errorDialogExists = TRUE;
  382.     return TRUE;
  383. }
  384.  
  385.  
  386. /* makeCsoPanelWorkProc
  387.    X work proc to create the CSO (ph) panel during spare cycles. */
  388.  
  389. static Boolean
  390. makeCsoPanelWorkProc(clientData)
  391. XtPointer    clientData;
  392. {
  393.     Widget        topLevel = (Widget) clientData;
  394.     makeCsoPanel(topLevel);
  395.     csoPanelExists = TRUE;
  396.     return TRUE;
  397. }
  398.  
  399.  
  400. /* makeIndexWorkProc
  401.    X work proc to create the Index Search panel during spare cycles. */
  402.  
  403. static Boolean
  404. makeIndexWorkProc(clientData)
  405. XtPointer    clientData;
  406. {
  407.     Widget        topLevel = (Widget) clientData;
  408.     makeIndexPanel(topLevel);
  409.     indexPanelExists = TRUE;
  410.     return TRUE;
  411. }
  412.  
  413.  
  414. /* makeOptionsWorkProc
  415.    X work proc to create the Options panel during spare cycles. */
  416.  
  417. static Boolean
  418. makeOptionsWorkProc(clientData)
  419. XtPointer    clientData;
  420. {
  421.     Widget        topLevel = (Widget) clientData;
  422.     makeOptionsPanel(topLevel);
  423.     optionsPanelExists = TRUE;
  424.     return TRUE;
  425. }
  426.  
  427.  
  428. /* makeSingleWorkProc
  429.    X work proc to create the Single Item panel during spare cycles. */
  430.  
  431. static Boolean
  432. makeSingleWorkProc(clientData)
  433. XtPointer    clientData;
  434. {
  435.     Widget        topLevel = (Widget) clientData;
  436.     makeSinglePanel(topLevel);
  437.     singlePanelExists = TRUE;
  438.     return TRUE;
  439. }
  440.  
  441.  
  442. /* markCurrentDirectory
  443.    set a bookmark at the current directory (by an event other than
  444.    the standard click on the bookmark button) */
  445.  
  446. void
  447. markCurrentDirectory()
  448. {
  449.     markProc(NULL, NULL, NULL);
  450. }
  451.  
  452.  
  453. /* doUserRequests
  454.    The main loop in the GUI process - await user events, and process them. */
  455.  
  456. void
  457. doUserRequests()
  458. {
  459.     saveWPID    = XtAppAddWorkProc (appcon, makeSaveDialogWorkProc,
  460.                     (XtPointer) topLevel);
  461.     indexWPID   = XtAppAddWorkProc (appcon, makeIndexWorkProc,
  462.                     (XtPointer) topLevel);
  463.     csoWPID        = XtAppAddWorkProc (appcon, makeCsoPanelWorkProc,
  464.                     (XtPointer) topLevel);
  465.     infoWPID    = XtAppAddWorkProc (appcon, makeInfoDialogWorkProc,
  466.                     (XtPointer) topLevel);
  467.     singleWPID  = XtAppAddWorkProc (appcon, makeSingleWorkProc,
  468.                     (XtPointer) topLevel);
  469.     optionsWPID = XtAppAddWorkProc (appcon, makeOptionsWorkProc,
  470.                     (XtPointer) topLevel);
  471.     errWPID        = XtAppAddWorkProc (appcon, makeErrorDialogWorkProc,
  472.                     (XtPointer) topLevel);
  473.  
  474.     XtAppMainLoop(appcon);
  475. }
  476.  
  477.  
  478. /* makeXThings
  479.    make things such as icons, bitmaps, and parsed translation tables
  480.    that the application will need */
  481.  
  482. #include "oneLine.h"
  483. #include "bitmaps/pgdown.xbm"
  484. #include "bitmaps/pgup.xbm"
  485. #include "bitmaps/pulldown.xbm"
  486. #include "bitmaps/check.xbm"
  487. #include "bitmaps/uncheck.xbm"
  488. #include <X11/bitmaps/gray3>
  489.  
  490. void
  491. makeXThings()
  492. {
  493.     wmDeleteAtom = XInternAtom(XtDisplay(topLevel), "WM_DELETE_WINDOW",
  494.                 False);
  495.                 
  496.     oneLineParsed = XtParseTranslationTable(OneLineTextTr);
  497.  
  498.     pageDownPixmap = XCreateBitmapFromData (XtDisplay(topLevel),
  499.                 RootWindowOfScreen(XtScreen(topLevel)),
  500.                         (char *) pgdown_bits,
  501.                         pgdown_width, pgdown_height);
  502.  
  503.     pageUpPixmap = XCreateBitmapFromData (XtDisplay(topLevel),
  504.                 RootWindowOfScreen(XtScreen(topLevel)),
  505.                         (char *) pgup_bits,
  506.                         pgup_width, pgup_height);
  507.  
  508.     pulldownPixmap = XCreateBitmapFromData (XtDisplay(topLevel),
  509.                 RootWindowOfScreen(XtScreen(topLevel)),
  510.                         (char *) pulldown_bits,
  511.                         pulldown_width,
  512.                         pulldown_height);
  513.  
  514.     gray = XCreatePixmapFromBitmapData (XtDisplay(topLevel),
  515.                 RootWindowOfScreen(XtScreen(topLevel)),
  516.                         (char *) gray3_bits,
  517.                         gray3_width, gray3_height,
  518.                 BlackPixelOfScreen(XtScreen(topLevel)),
  519.                 WhitePixelOfScreen(XtScreen(topLevel)),
  520.                 DefaultDepthOfScreen(XtScreen(topLevel))
  521.                         );
  522.  
  523.     checkPixmap = XCreateBitmapFromData (XtDisplay(topLevel),
  524.                 RootWindowOfScreen(XtScreen(topLevel)),
  525.                         (char *) check_bits,
  526.                         check_width, check_height);
  527.  
  528.     uncheckPixmap = XCreateBitmapFromData (XtDisplay(topLevel),
  529.                 RootWindowOfScreen(XtScreen(topLevel)),
  530.                         (char *) uncheck_bits,
  531.                         uncheck_width, uncheck_height);
  532. }
  533.  
  534.  
  535. /* getSelectedItem
  536.    get the currently selected gopher item */
  537.  
  538. gopherItemP
  539. getSelectedItem()
  540. {
  541.     return whichItemSelected();
  542. }
  543.  
  544.  
  545. /* showError
  546.    Cause an error message to be displayed on the user's screen. */
  547.  
  548. void
  549. showError(message)
  550. char    *message;
  551. {
  552.     if (windowStarted) {
  553.         if (! errorDialogExists) {
  554.             makeErrorDialog(topLevel);
  555.             errorDialogExists = TRUE;
  556.             if (errWPID != nullWPID) XtRemoveWorkProc (errWPID);
  557.         }
  558.         displayError(message, False);
  559.     } else {
  560.         fprintf (stderr, "NOTE!\n%s\n", message);
  561.     }
  562.     LOG (logFP, "ERROR:\n%s\n", message);
  563. }
  564.  
  565.  
  566. /* showFatalError
  567.    Cause a fatal error message to be displayed on the user's screen. */
  568.  
  569. void
  570. showFatalError(message)
  571. char    *message;
  572. {
  573.     if (windowStarted) {
  574.         if (! errorDialogExists) {
  575.             makeErrorDialog(topLevel);
  576.             errorDialogExists = TRUE;
  577.             if (errWPID != nullWPID) XtRemoveWorkProc (errWPID);
  578.         }
  579.         displayError(message, True);
  580.     } else {
  581.         fprintf (stderr, "NOTE: Unrecoverable error!\n%s\n", message);
  582.     }
  583.     LOG (logFP, "FATAL ERROR:\n%s\n", message);
  584. }
  585.  
  586.  
  587. /* showInfo
  588.    Cause an information message to be displayed on the user's screen. */
  589.  
  590. void
  591. showInfo(message)
  592. char    *message;
  593. {
  594.     if (windowStarted) {
  595.         if (! infoDialogExists) {
  596.             makeInfoDialog(topLevel);
  597.             infoDialogExists = TRUE;
  598.             if (infoWPID != nullWPID) XtRemoveWorkProc (infoWPID);
  599.         }
  600.         displayInfo(message);
  601.     } else {
  602.         fprintf (stderr, "NOTE!\n%s\n", message);
  603.     }
  604. }
  605.  
  606.  
  607. /* showStatus
  608.    indicate status of the gopher process to the user by messages, icons,
  609.    and/or cursor changes. */
  610.  
  611. void
  612. showStatus(message, statType, host, port)
  613. char        *message;
  614. statusType    statType;
  615. char        *host;
  616. int        port;
  617. {
  618.  
  619.     if (! windowStarted) return;
  620.  
  621.         if (statType != STAT_USER) {
  622.         displayStatusPanel(statType, message, host, port);
  623.     } else {
  624.         removeStatusPanel();
  625.     }
  626. }
  627.  
  628.  
  629. /* displayCurrent
  630.    display the current directory. */
  631.  
  632. void
  633. displayCurrent()
  634. {
  635.     gopherItemP    gi;
  636.     int        i, need;
  637.     static    int    dirStringListLen = 0;
  638.     static    char    **dirStringList = NULL;
  639.     gopherDirP      current = getCurrentDir();
  640.  
  641.  
  642.     if (current != NULL) {
  643.         LOG(logFP,
  644.         "Current directory: \'%s'\n\tSelector \'%s\'\n\tat \'%s\' %d\n",
  645.             USER_STRING(current->selectorItem),
  646.             vStringValue(&(current->selectorItem->selector)),
  647.             current->selectorItem->host,
  648.             current->selectorItem->port);
  649.     }
  650.  
  651.     if (!windowStarted) return;
  652.     if (current != NULL) {
  653.         if (current->created == NOT_LOADED)
  654.             updateDirectory(current);
  655.     }
  656.  
  657.     /* The array of string pointers is allocated a reasonably
  658.        large amount initially.  After this, if more are needed,
  659.        the current array is freed, then the new required number
  660.        is allocated.  */
  661.  
  662.     if (current != NULL) {
  663.         need = itemListLength(&(current->contents)) + 1;
  664.     } else {
  665.         need = 0;
  666.     }
  667.     if (need > dirStringListLen) {
  668.         need = need > MIN_DIR_STRING_LIST_LEN ?
  669.                 need : MIN_DIR_STRING_LIST_LEN;
  670.         if (dirStringList != NULL) free(dirStringList);
  671.         dirStringList = NULL;
  672.         if ((dirStringList = (char **) malloc(need * sizeof(char *)))
  673.                                 == NULL) {
  674.             showError(
  675. "Unable to allocate sufficient memory to display this directory.");
  676.             changeDirList(emptyList);
  677.             return;
  678.         }
  679.     }
  680.  
  681.  
  682.     if (current != NULL) {
  683.         changeDirLabel(USER_STRING(current->selectorItem));
  684.     } else {
  685.         changeDirLabel("Empty Directory");
  686.     }
  687.  
  688.     i = 0;
  689.     if (current != NULL) {
  690.         if ((gi = current->contents.first) != NULL) {
  691.             while ( gi != NULL) {
  692.                 dirStringList[i] = USER_STRING_PREFIX(gi);
  693.                 i++;
  694.                 gi = nextItem(gi);
  695.             }
  696.         }
  697.     }
  698.  
  699.     dirStringList[i] = (char *) NULL;
  700.     
  701.     changeDirList(dirStringList);
  702.  
  703.     return;
  704. }
  705.  
  706.  
  707. /* displayBookmarks
  708.    display the current bookmark list. */
  709.  
  710. void
  711. displayBookmarks()
  712. {
  713.     gopherItemP    gi;
  714.     int        i, need;
  715.     static    int    markStringListLen = 0;
  716.     static    char    **markStringList = NULL;
  717.  
  718.     if (!windowStarted) return;
  719.  
  720.     /* The array of string pointers is allocated a reasonably
  721.        large amount initially.  After this, if more are needed,
  722.        the current array is freed, then the new required number
  723.        is allocated.  */
  724.  
  725.     need = markListLength() + 1;
  726.     if (need > markStringListLen) {
  727.         need = need > MIN_MARK_STRING_LIST_LEN ?
  728.                 need : MIN_MARK_STRING_LIST_LEN;
  729.         if (markStringList != NULL) free(markStringList);
  730.         markStringList = NULL;
  731.         if ((markStringList = (char **) malloc(need * sizeof(char *)))
  732.                                 == NULL) {
  733.             showError(
  734. "Unable to allocate sufficient memory to display the bookmark list.");
  735.             changeMarkList(emptyList);
  736.             return;
  737.         }
  738.     }
  739.  
  740.     i = 0;
  741.     if ((gi = firstMark()) != NULL) {
  742.         while (gi != NULL) {
  743.             markStringList[i] = USER_STRING_PREFIX(gi);
  744.             i++;
  745.             gi = nextItem(gi);
  746.         }
  747.     }
  748.  
  749.     markStringList[i] = (char *) NULL;
  750.     
  751.     changeMarkList(markStringList);
  752.  
  753.     return;
  754. }
  755.  
  756.  
  757. /* checkPanelButtons
  758.    ensure that the panel buttons have proper sensitivity. */
  759.  
  760. void
  761. checkPanelButtons()
  762. {
  763.     checkButtonState(BS_all);
  764. }
  765.  
  766.  
  767. /* clearBookmarks
  768.    properly clear the bookmark list. */
  769.  
  770. void
  771. clearBookmarks()
  772. {
  773.     unmarkAllProc(NULL, NULL, NULL);
  774. }
  775.  
  776.  
  777. /* showFile
  778.    display a file on the screen. */
  779.  
  780. void
  781. showFile(gi, title, fileName, indexString)
  782. gopherItemP    gi;
  783. char        *title;
  784. char        *fileName;
  785. char        *indexString;
  786. {
  787.  
  788.     if (! windowStarted) return;
  789.  
  790.     if (! saveDialogExists) {
  791.         makeSaveDialog(topLevel);
  792.         saveDialogExists = TRUE;
  793.         if (saveWPID != nullWPID) XtRemoveWorkProc (saveWPID);
  794.     }
  795.  
  796.     if (indexString == NULL) {
  797.         displayTempFile(topLevel, fileTextClass, gi, title, fileName);
  798.     } else {
  799.         displayIndexTempFile(topLevel, fileTextClass, gi, title,
  800.                     fileName, indexString);
  801.     }
  802.  
  803.     return;
  804. }
  805.  
  806.  
  807. /* showNameServer
  808.    display a CSO name server panel. */
  809.  
  810. void
  811. showNameServer(title, s)
  812. char    *title;
  813. int    s;
  814. {
  815.  
  816.     if (! windowStarted) return;
  817.  
  818.     LOG (logFP, "CSO name server at:%s\n", title);
  819.  
  820.     if (! csoPanelExists) {
  821.         makeCsoPanel(topLevel);
  822.         csoPanelExists = TRUE;
  823.         if (csoWPID != nullWPID) XtRemoveWorkProc (csoWPID);
  824.     }
  825.     if (! displayCsoPanel(title, s)) {
  826.         showError(
  827.         "Cannot display CSO Name Server\n(Is one already active?)");
  828.     }
  829.  
  830.     return;
  831. }
  832.  
  833.  
  834. /* showIndex
  835.    display a Index search panel. */
  836.  
  837. void
  838. showIndex(gi)
  839. gopherItemP    gi;
  840. {
  841.  
  842.     if (! windowStarted) return;
  843.  
  844.     LOG (logFP, "Index search:%s\n", USER_STRING(gi));
  845.  
  846.     if (! indexPanelExists) {
  847.         makeIndexPanel(topLevel);
  848.         indexPanelExists = TRUE;
  849.         if (indexWPID != nullWPID) XtRemoveWorkProc (indexWPID);
  850.     }
  851.  
  852.     displayIndexPanel((XtPointer) gi, USER_STRING(gi));
  853.  
  854.     return;
  855. }
  856.  
  857.  
  858. /* showOptionsPanel
  859.    display the options panel. */
  860.  
  861. void
  862. showOptionsPanel()
  863. {
  864.  
  865.     if (! windowStarted) return;
  866.  
  867.     if (! optionsPanelExists) {
  868.         makeOptionsPanel(topLevel);
  869.         optionsPanelExists = TRUE;
  870.         if (optionsWPID != nullWPID) XtRemoveWorkProc (optionsWPID);
  871.     }
  872.  
  873.     displayOptionsPanel();
  874.  
  875.     return;
  876. }
  877.  
  878.  
  879. /* showSinglePanel
  880.    display the single gopher item entry panel. */
  881.  
  882. void
  883. showSinglePanel()
  884. {
  885.  
  886.     if (! windowStarted) return;
  887.  
  888.     if (! singlePanelExists) {
  889.         makeSinglePanel(topLevel);
  890.         singlePanelExists = TRUE;
  891.         if (singleWPID != nullWPID) XtRemoveWorkProc (singleWPID);
  892.     }
  893.  
  894.     displaySinglePanel();
  895.  
  896.     return;
  897. }
  898.  
  899.  
  900. /* showHelp
  901.    show a help item in a text window */
  902.  
  903. void
  904. showHelp(key)
  905. char    *key;
  906. {
  907.         char    *string;
  908.     char    title[HELP_SEC_TITLE_LEN];
  909.  
  910.         string = getHelpText(key, title);
  911.         if (string == NULL)
  912.                 showError ("No help is available.");
  913.         else if (title[0] == '\0') 
  914.         displayTextString(topLevel, helpTextClass, (gopherItemP) NULL,
  915.                     "Gopher Assistance", string);
  916.     else 
  917.         displayTextString(topLevel, helpTextClass, (gopherItemP) NULL,
  918.                     title, string);
  919.     
  920.     return;
  921. }
  922.  
  923.  
  924. /* showItemInfo
  925.    show information about a gopher item in a text window */
  926.  
  927. void
  928. showItemInfo(gi)
  929. gopherItemP    gi;
  930. {
  931.         char    *string;
  932.  
  933.         string = getItemInfoText(gi, 0);
  934.         if (string == NULL)
  935.                 showError ("No information on this item is available.");
  936.     else 
  937.         displayTextString(topLevel, infoTextClass, (gopherItemP) NULL,
  938.                     "Information", string);
  939.     
  940.     return;
  941. }
  942.  
  943.  
  944. /* setPopupGeometry
  945.    preset the geometry specification for topLevelShell's before they
  946.    are realized. */
  947.  
  948. void
  949. setPopupGeometry(w, placement)
  950. Widget            w;
  951. popupPosResources    *placement;
  952. {
  953.     Arg        args[5];
  954.     Cardinal    n;
  955.     Position    rootX, rootY;
  956.     Dimension    popupWidth, popupHeight;
  957.     Dimension    screenWidth, screenHeight;
  958.  
  959.  
  960.     if (w == NULL) return;
  961.     if (XtClass(w) != topLevelShellWidgetClass) return;
  962.     if (placement->positionFrom == from_none) return;
  963.  
  964.     /* the value "+0+0" is sufficient to let us 
  965.        move the window later when it is displayed. */
  966.  
  967.     XtSetArg(args[0], XtNgeometry, "+0+0");
  968.     XtSetValues(w, args, (Cardinal) 1);
  969.  
  970.     return;
  971. }
  972.  
  973.  
  974. /*  findPopupPosition
  975.     Auxiliary routine used by positionAPopup.  This routine computes the
  976.     target position on the root window, but doesn't actually do the move */
  977.  
  978. void
  979. findPopupPosition(w, fromWidget, placement, rootX, rootY)
  980. Widget            w;
  981. Widget            fromWidget;
  982. popupPosResources    *placement;
  983. Position        *rootX, *rootY;
  984. {
  985.        /*
  986.          w         is the popup widget.
  987.          fromWidget    is the shell widget to position relative to
  988.             (for from_main or from_widget)
  989.          placement    is a struct containing the positioning information.    
  990.        */
  991.     Arg        args[5];
  992.     Cardinal    n;
  993.     Dimension    popupWidth, popupHeight;
  994.     Dimension    screenWidth, screenHeight;
  995.  
  996.  
  997.     *rootX = 0;
  998.     *rootY = 0;
  999.  
  1000.     if (w == NULL) return;
  1001.     if (placement->positionFrom == from_none) return;
  1002.  
  1003.     screenWidth = WidthOfScreen(XtScreen(w));
  1004.     screenHeight = HeightOfScreen(XtScreen(w));
  1005.  
  1006.     if (XtClass(w) == transientShellWidgetClass) {
  1007.         XtRealizeWidget(w);
  1008.     }
  1009.  
  1010.     /* find a reference point */
  1011.  
  1012.     switch (placement->positionFrom) {
  1013.         case from_pointer:
  1014.         {
  1015.             Window    root, child;
  1016.             int        ptrX, ptrY, winX, winY;
  1017.             unsigned int    keysButtons;
  1018.  
  1019.             XQueryPointer(XtDisplay(w), XtWindow(XtParent(w)),
  1020.                 &root, &child, &ptrX, &ptrY, &winX, &winY,
  1021.                 &keysButtons);
  1022.             
  1023.             *rootX = (Position) ptrX;
  1024.             *rootY = (Position) ptrY;
  1025.         }
  1026.         break;
  1027.  
  1028.         case from_main:
  1029.         case from_widget:
  1030.         {
  1031.             Dimension    panelWidth, panelHeight;
  1032.             Position    relX, relY;
  1033.  
  1034.             n = 0;
  1035.             XtSetArg(args[n], XtNwidth, &panelWidth);  n++;
  1036.             XtSetArg(args[n], XtNheight, &panelHeight);  n++;
  1037.             XtGetValues(fromWidget, args, n);
  1038.  
  1039.             if (placement->xPercent) {
  1040.                 relX = ((int) panelWidth * placement->xPosition)
  1041.                         / 100;
  1042.             } else {
  1043.                 relX = placement->xPosition;
  1044.             }
  1045.             if (placement->yPercent) {
  1046.                 relY = ((int) panelHeight * placement->yPosition)
  1047.                     / 100;
  1048.             } else {
  1049.                 relY = placement->yPosition;
  1050.             }
  1051.             XtTranslateCoords(fromWidget, relX, relY, rootX, rootY);
  1052.         }
  1053.         break;
  1054.  
  1055.         case from_screen:
  1056.         {
  1057.             if (placement->xPercent) {
  1058.                 *rootX = ((int) screenWidth * placement->xPosition)
  1059.                     / 100;
  1060.             } else {
  1061.                 *rootX = placement->xPosition;
  1062.             }
  1063.  
  1064.             if (placement->yPercent) {
  1065.                 *rootY = ((int) screenHeight * placement->yPosition)
  1066.                     / 100;
  1067.             } else {
  1068.                 *rootY = placement->yPosition;
  1069.             }
  1070.         }
  1071.         break;
  1072.     }
  1073.  
  1074.     /* apply justification left/right, top/bottom */
  1075.  
  1076.     n = 0;
  1077.     XtSetArg(args[n], XtNwidth, &popupWidth);  n++;
  1078.     XtSetArg(args[n], XtNheight, &popupHeight);  n++;
  1079.     XtGetValues(w, args, n);
  1080.  
  1081.     if (placement->horizontalJustification == justify_center)
  1082.                         *rootX -= popupWidth / 2;
  1083.     else if (placement->horizontalJustification == justify_bottom_right)
  1084.                         *rootX -= popupWidth;
  1085.  
  1086.     if (placement->verticalJustification == justify_center) 
  1087.                         *rootY -= popupHeight / 2;
  1088.     else if (placement->verticalJustification == justify_bottom_right) 
  1089.                         *rootY -= popupHeight;
  1090.  
  1091.     /* force the popup to be on screen */
  1092.  
  1093.     if (*rootX < 0)    *rootX = 0;
  1094.     else if ((int) *rootX + (int) popupWidth > (int) screenWidth)
  1095.             *rootX = screenWidth - popupWidth;
  1096.  
  1097.     if (*rootY < 0)    *rootY = 0;
  1098.     else if ((int) *rootY + (int) popupHeight > (int) screenHeight)
  1099.             *rootY = screenHeight - popupHeight;
  1100. }
  1101.  
  1102.  
  1103. /* positionAPopup
  1104.    set the position of a popup window. */
  1105.  
  1106. void
  1107. positionAPopup(w, fromWidget, placement)
  1108. Widget            w;
  1109. Widget            fromWidget;
  1110. popupPosResources    *placement;
  1111. {
  1112.        /*
  1113.          w         is the popup widget.
  1114.          fromWidget    is the shell widget to position relative to
  1115.             (for from_main or from_widget)
  1116.          placement    is a struct containing the positioning information.    
  1117.        */
  1118.     Arg        args[5];
  1119.     Cardinal    n;
  1120.     Position    rootX, rootY;
  1121.  
  1122.  
  1123.     if (w == NULL) return;
  1124.     if (placement->positionFrom == from_none) return;
  1125.  
  1126.     findPopupPosition(w, fromWidget, placement, &rootX, &rootY);
  1127.  
  1128.     if (XtClass(w) == transientShellWidgetClass) {
  1129.         /*
  1130.         XtMoveWidget(w, (Position) rootX, (Position) rootY);
  1131.         */
  1132.         n = 0;
  1133.         XtSetArg(args[n], XtNx, rootX);  n++;
  1134.         XtSetArg(args[n], XtNy, rootY);  n++;
  1135.         XtSetValues(w, args, n);
  1136.     } else if (XtIsRealized(w)) {
  1137.         XMoveWindow(XtDisplay(w), XtWindow(w),
  1138.                 (int) rootX, (int) rootY);
  1139.     } else {
  1140.  
  1141.         /* we likely won't get here because most popups
  1142.            are realized earlier in order to install the
  1143.            ICCCM event handling easily. */
  1144.  
  1145.         static char    geom[16];
  1146.  
  1147.         sprintf(geom, "+%d+%d", (int) rootX, (int) rootY);
  1148.         XtSetArg(args[0], XtNgeometry, geom);
  1149.         XtSetValues(w, args, (Cardinal) 1);
  1150.     }
  1151.  
  1152.     return;
  1153. }
  1154.  
  1155.  
  1156. /* setTextWidgetSize
  1157.    Use the selected font size and other attributes to set the
  1158.    size of a text widget.  This routine should be called just
  1159.    after a text widget is created. */
  1160.  
  1161. void
  1162. setTextWidgetSize(textWidget, width, height)
  1163. Widget    textWidget;
  1164. int    width, height;
  1165. {
  1166.     XawTextWrapMode    wrap;
  1167.     XFontStruct    *textFontStruct;
  1168.     int        direction, ascent, descent;
  1169.     XCharStruct    overall;
  1170.     Position    topMargin, bottomMargin;
  1171.     Position    leftMargin, rightMargin;
  1172.     Dimension    w, h;
  1173.     Arg        args[10];
  1174.     Cardinal    n;
  1175.  
  1176.     if (textWidget == NULL) return;
  1177.  
  1178.     n=0;
  1179.     if (height > 1) {
  1180.         XtSetArg(args[n], XtNwrap, &wrap);  n++;
  1181.     }
  1182.     XtSetArg(args[n], XtNfont, &textFontStruct);  n++;
  1183.     XtSetArg(args[n], XtNtopMargin, &topMargin);  n++;
  1184.     XtSetArg(args[n], XtNbottomMargin, &bottomMargin);  n++;
  1185.     XtSetArg(args[n], XtNleftMargin, &leftMargin);  n++;
  1186.     XtSetArg(args[n], XtNrightMargin, &rightMargin);  n++;
  1187.     XtGetValues(textWidget, args, n);
  1188.     if (height > 1) {
  1189.         if (wrap == XawtextWrapNever) {
  1190.             n=0;
  1191.             XtSetArg(args[n], XtNscrollHorizontal,
  1192.                 XawtextScrollWhenNeeded);  n++;
  1193.             XtSetValues(textWidget, args, n);
  1194.         }
  1195.     } 
  1196.  
  1197.     /* use some randomly-sized characters to get width in case
  1198.        it is a proportionately-spaced font */
  1199.  
  1200.     XTextExtents(textFontStruct, "mljf", 4,
  1201.         &direction, &ascent, &descent, &overall);
  1202.  
  1203.     w = (Dimension) ( leftMargin + rightMargin + 
  1204.               (int) (overall.width * ( (float) width / 4.0) ) );
  1205.     h = (Dimension) ( (topMargin + bottomMargin) +
  1206.               ( (ascent + descent) * height) );
  1207.     
  1208.     /* The following is a hack.
  1209.        The scrollbar steals away space from the text content
  1210.        of the window if and when it is displayed.  If
  1211.        "scrollWhenNeeded" is set, then the scrollbar does not
  1212.        exist yet and may not ever exist.  So we have no way
  1213.        to find out its width.
  1214.  
  1215.        We're not as likely to have a horizontal bar as a vertical
  1216.        one, so ignore the horizontal one.  It's less crucial.
  1217.        However, we'd like to always provide a text display which
  1218.        is at least 80 characters wide by default.
  1219.  
  1220.        So, We'll just add 14 pixels for the scrollbar thickness.
  1221.        Which is the default provided in the Xaw Scrollbar.c
  1222.        source.  I hate doing this, but there seems to be no
  1223.        other way.  We'll similarly add 2 pixels for border
  1224.        width, then quietly slink off into the night.
  1225.     */
  1226.     w = w + 16;
  1227.  
  1228.     n=0;
  1229.     XtSetArg(args[n], XtNwidth, w);  n++;
  1230.     XtSetArg(args[n], XtNheight, h); n++;
  1231.     XtSetValues(textWidget, args, n);
  1232. }
  1233.  
  1234.  
  1235. /* getTextSize
  1236.    To find out the size in pixels required to hold a certain number of
  1237.    rows and columns of text, given the font and other attributes
  1238.    of a widget.  This routine should only be called for widgets
  1239.    which contain text, such as label and list. */
  1240.  
  1241. void
  1242. getTextSize(someWidget, width, height, w, h)
  1243. Widget        someWidget;
  1244. int        width, height;
  1245. Dimension    *w, *h;
  1246. {
  1247.     XawTextWrapMode    wrap;
  1248.     XFontStruct    *textFontStruct;
  1249.     int        direction, ascent, descent;
  1250.     XCharStruct    overall;
  1251.     Position    topMargin, bottomMargin;
  1252.     Arg        args[10];
  1253.     Cardinal    n;
  1254.  
  1255.     if (someWidget == NULL) return;
  1256.  
  1257.     n=0;
  1258.     XtSetArg(args[n], XtNfont, &textFontStruct);  n++;
  1259.     XtGetValues(someWidget, args, n);
  1260.  
  1261.     /* use some randomly-sized characters to get width in case
  1262.        it is a proportionately-spaced font */
  1263.  
  1264.     XTextExtents(textFontStruct, "mljf", 4,
  1265.         &direction, &ascent, &descent, &overall);
  1266.  
  1267.     *w = (Dimension) ((int) (overall.width * ( (float) width / 4.0) ) );
  1268.     *h = (Dimension) (ascent + descent) * height;
  1269. }
  1270.  
  1271.  
  1272. static BOOLEAN    ding = FALSE;
  1273. #define MAX_WAIT_TIME    3000    /* milliseconds */
  1274.  
  1275. /* maxWaitTimeProc
  1276.    we don't want to be dispatching events for more than this time */
  1277.  
  1278. static void
  1279. maxWaitTimeProc(clientData, id)
  1280. XtPointer    clientData;
  1281. XtIntervalId    *id;
  1282. {
  1283.     ding = TRUE;
  1284. }
  1285.  
  1286.  
  1287. /* WaitForAllPendingEventsAndExpose
  1288.    Clears out the event queue and optionally waits until it sees
  1289.    an expose event for a specific window.  In the latter case,
  1290.    it will also offer a timeout to prevent indefinite hangs. */
  1291.  
  1292. void
  1293. WaitForAllPendingEventsAndExpose(dpy, needToSee)
  1294. Display        *dpy;
  1295. Window        needToSee;
  1296. {
  1297.     static XEvent    event;
  1298.     BOOLEAN        gotExposed=FALSE;
  1299.     XtIntervalId    waitTimerId = (XtIntervalId) 0;
  1300.  
  1301.     XSync(dpy, False);
  1302.     if (needToSee == (Window) NULL) {
  1303.         while( XtAppPending (appcon) ) {
  1304.             XtAppNextEvent(appcon, &event);
  1305.             XtDispatchEvent (&event);
  1306.         }
  1307.     } else {
  1308.  
  1309.         /* empty the event queue, and keep doing so until we
  1310.            see a specific expose event or until were tired
  1311.            of waiting. */
  1312.  
  1313.         waitTimerId = XtAppAddTimeOut(appcon, MAX_WAIT_TIME,
  1314.                     maxWaitTimeProc, NULL);
  1315.         ding = FALSE;
  1316.         while( XtAppPending (appcon)  ||  (!gotExposed  &&  !ding)) {
  1317.             XtAppNextEvent(appcon, &event);
  1318.             if (event.type == Expose  &&
  1319.                     event.xexpose.window == needToSee) {
  1320.                 gotExposed = TRUE;
  1321.             }
  1322.  
  1323.             XtDispatchEvent (&event);
  1324.         }
  1325.         if (! ding) {
  1326.             XtRemoveTimeOut(waitTimerId);
  1327.         }
  1328.     }
  1329. }
  1330.  
  1331.  
  1332.